
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       rc_channel.h
  * @author     baiyang
  * @date       2021-8-8
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include <stdint.h>
#include <stdbool.h>

#include "rc.h"
/*-----------------------------------macro------------------------------------*/
/**
 * rc_container_of - return the member address of ptr, if the type of ptr is the
 * struct type.
 */
#define rc_container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

// pwm value above which the option will be invoked:
#define AUX_PWM_TRIGGER_HIGH  1700

// pwm value below which the option will be disabled:
#define AUX_PWM_TRIGGER_LOW   1300

#define  RC_MIN_LIMIT_PWM     900
// pwm value above which we consider that Radio value is invalid
#define  RC_MAX_LIMIT_PWM     2200

// pwm value above which we condider that Radio min value is invalid
#define  RC_CALIB_MIN_LIMIT_PWM       1300
// pwm value under which we condider that Radio max value is invalid
#define  RC_CALIB_MAX_LIMIT_PWM       1700

// pwm value above which the switch/button will be invoked:
#define  AUX_SWITCH_PWM_TRIGGER_HIGH  1800
// pwm value below which the switch/button will be disabled:
#define  AUX_SWITCH_PWM_TRIGGER_LOW   1200
/*----------------------------------typedef-----------------------------------*/
typedef int8_t modeswitch_pos_t;

typedef enum {
    RC_CHANNEL_TYPE_ANGLE = 0,
    RC_CHANNEL_TYPE_RANGE = 1,
} RC_ChannelType;

// auxillary switch handling (n.b.: we store this as 2-bits!):
typedef enum {
    RC_LOW,       // indicates auxiliary switch is in the low position (pwm <1200)
    RC_MIDDLE,    // indicates auxiliary switch is in the middle position (pwm >1200, <1800)
    RC_HIGH       // indicates auxiliary switch is in the high position (pwm >1800)
} RC_AuxSwitchPos;

// Structure used to detect and debounce switch changes
typedef struct {
    int8_t debounce_position;       //初始化为-1
    int8_t current_position;        //初始化为-1
    uint32_t last_edge_time_ms;
} RC_SwitchState;

// Aux Switch enumeration
typedef enum {
    RC_DO_NOTHING =           0, // aux switch disabled
    RC_FLIP =                 2, // flip
    RC_SIMPLE_MODE =          3, // change to simple mode
    RC_RTL =                  4, // change to RTL flight mode
    RC_SAVE_TRIM =            5, // save current position as level
    RC_SAVE_WP =              7, // save mission waypoint or RTL if in auto mode
    RC_CAMERA_TRIGGER =       9, // trigger camera servo or relay
    RC_RANGEFINDER =         10, // allow enabling or disabling rangefinder in flight which helps avoid surface tracking when you are far above the ground
    RC_FENCE =               11, // allow enabling or disabling fence in flight
    RC_RESETTOARMEDYAW =     12, // UNUSED
    RC_SUPERSIMPLE_MODE =    13, // change to simple mode in middle, super simple at top
    RC_ACRO_TRAINER =        14, // low = disabled, middle = leveled, high = leveled and limited
    RC_SPRAYER =             15, // enable/disable the crop sprayer
    RC_AUTO =                16, // change to auto flight mode
    RC_AUTOTUNE =            17, // auto tune
    RC_LAND =                18, // change to LAND flight mode
    RC_GRIPPER =             19, // Operate cargo grippers low=off, middle=neutral, high=on
    RC_PARACHUTE_ENABLE  =   21, // Parachute enable/disable
    RC_PARACHUTE_RELEASE =   22, // Parachute release
    RC_PARACHUTE_3POS =      23, // Parachute disable, enable, release with 3 position switch
    RC_MISSION_RESET =       24, // Reset auto mission to start from first command
    RC_ATTCON_FEEDFWD =      25, // enable/disable the roll and pitch rate feed forward
    RC_ATTCON_ACCEL_LIM =    26, // enable/disable the roll, pitch and yaw accel limiting
    RC_RETRACT_MOUNT =       27, // Retract Mount
    RC_RELAY =               28, // Relay pin on/off (only supports first relay)
    RC_LANDING_GEAR =        29, // Landing gear controller
    RC_LOST_VEHICLE_SOUND =  30, // Play lost vehicle sound
    RC_MOTOR_ESTOP =         31, // Emergency Stop Switch
    RC_MOTOR_INTERLOCK =     32, // Motor On/Off switch
    RC_BRAKE =               33, // Brake flight mode
    RC_RELAY2 =              34, // Relay2 pin on/off
    RC_RELAY3 =              35, // Relay3 pin on/off
    RC_RELAY4 =              36, // Relay4 pin on/off
    RC_THROW =               37, // change to THROW flight mode
    RC_AVOID_ADSB =          38, // enable AP_Avoidance library
    RC_PRECISION_LOITER =    39, // enable precision loiter
    RC_AVOID_PROXIMITY =     40, // enable object avoidance using proximity sensors (ie. horizontal lidar)
    RC_ARMDISARM =           41, // arm or disarm vehicle
    RC_SMART_RTL =           42, // change to SmartRTL flight mode
    RC_INVERTED  =           43, // enable inverted flight
    RC_WINCH_ENABLE =        44, // winch enable/disable
    RC_WINCH_CONTROL =       45, // winch control
    RC_RC_OVERRIDE_ENABLE =  46, // enable RC Override
    RC_USER_FUNC1 =          47, // user function #1
    RC_USER_FUNC2 =          48, // user function #2
    RC_USER_FUNC3 =          49, // user function #3
    RC_LEARN_CRUISE =        50, // learn cruise throttle (Rover)
    RC_MANUAL       =        51, // manual mode
    RC_ACRO         =        52, // acro mode
    RC_STEERING     =        53, // steering mode
    RC_HOLD         =        54, // hold mode
    RC_GUIDED       =        55, // guided mode
    RC_LOITER       =        56, // loiter mode
    RC_FOLLOW       =        57, // follow mode
    RC_CLEAR_WP     =        58, // clear waypoints
    RC_SIMPLE       =        59, // simple mode
    RC_ZIGZAG       =        60, // zigzag mode
    RC_ZIGZAG_SaveWP =       61, // zigzag save waypoint
    RC_COMPASS_LEARN =       62, // learn compass offsets
    RC_SAILBOAT_TACK =       63, // rover sailboat tack
    RC_REVERSE_THROTTLE =    64, // reverse throttle input
    RC_GPS_DISABLE  =        65, // disable GPS for testing
    RC_RELAY5 =              66, // Relay5 pin on/off
    RC_RELAY6 =              67, // Relay6 pin on/off
    RC_STABILIZE =           68, // stabilize mode
    RC_POSHOLD   =           69, // poshold mode
    RC_ALTHOLD   =           70, // althold mode
    RC_FLOWHOLD  =           71, // flowhold mode
    RC_CIRCLE    =           72, // circle mode
    RC_DRIFT     =           73, // drift mode
    RC_SAILBOAT_MOTOR_3POS = 74, // Sailboat motoring 3pos
    RC_SURFACE_TRACKING =    75, // Surface tracking upwards or downwards
    RC_STANDBY  =            76, // Standby mode
    RC_TAKEOFF   =           77, // takeoff
    RC_RUNCAM_CONTROL =      78, // control RunCam device
    RC_RUNCAM_OSD_CONTROL =  79, // control RunCam OSD
    RC_VISODOM_CALIBRATE  =  80, // calibrate visual odometry camera's attitude
    RC_DISARM =              81, // disarm vehicle
    RC_Q_ASSIST =            82, // disable, enable and force Q assist
    RC_ZIGZAG_Auto =         83, // zigzag auto switch
    RC_AIRMODE =             84, // enable / disable airmode for copter
    RC_GENERATOR   =         85, // generator control
    RC_TER_DISABLE =         86, // disable terrain following in CRUISE/FBWB modes
    RC_CROW_SELECT =         87, // select CROW mode for diff spoilers;high disables,mid forces progressive
    RC_SOARING =             88, // three-position switch to set soaring mode
    RC_LANDING_FLARE =       89, // force flare, throttle forced idle, pitch to LAND_PITCH_CD, tilts up
    RC_EKF_POS_SOURCE =      90, // change EKF position source between primary, secondary and tertiary sources
    RC_ARSPD_CALIBRATE=      91, // calibrate airspeed ratio 
    RC_FBWA =                92, // Fly-By-Wire-A
    RC_RELOCATE_MISSION =    93, // used in separate branch MISSION_RELATIVE
    RC_VTX_POWER =           94, // VTX power level
    RC_FBWA_TAILDRAGGER =    95, // enables FBWA taildragger takeoff mode. Once this feature is enabled it will stay enabled until the aircraft goes above TKOFF_TDRAG_SPD1 airspeed, changes mode, or the pitch goes above the initial pitch when this is engaged or goes below 0 pitch. When enabled the elevator will be forced to TKOFF_TDRAG_ELEV. This option allows for easier takeoffs on taildraggers in FBWA mode, and also makes it easier to test auto-takeoff steering handling in FBWA.
    RC_MODE_SWITCH_RESET =   96, // trigger re-reading of mode switch
    RC_WIND_VANE_DIR_OFSSET= 97, // flag for windvane direction offset input, used with windvane type 2

    // entries from 100 onwards are expected to be developer
    // options used for testing
    RC_KILL_IMU1 =          100, // disable first IMU (for IMU failure testing)
    RC_KILL_IMU2 =          101, // disable second IMU (for IMU failure testing)
    RC_CAM_MODE_TOGGLE =    102, // Momentary switch to cycle camera modes
    RC_EKF_LANE_SWITCH =    103, // trigger lane switch attempt
    RC_EKF_YAW_RESET =      104, // trigger yaw reset attempt
    RC_GPS_DISABLE_YAW =    105, // disable GPS yaw for testing
    RC_DISABLE_AIRSPEED_USE = 106, // equivalent to AIRSPEED_USE 0
    // if you add something here, make sure to update the documentation of the parameter in RC_Channel.cpp!
    // also, if you add an option >255, you will need to fix duplicate_options_exist

    // inputs from 200 will eventually used to replace RCMAP
    RC_ROLL =               201, // roll input
    RC_PITCH =              202, // pitch input
    RC_THROTTLE =           203, // throttle pilot input
    RC_YAW =                204, // yaw pilot input
    RC_MAINSAIL =           207, // mainsail input
    RC_FLAP =               208, // flap input
    RC_FWD_THR =            209, // VTOL manual forward throttle
    RC_AIRBRAKE =           210, // manual airbrake control
    RC_WALKING_HEIGHT =     211, // walking robot height input

    // inputs for the use of onboard lua scripting
    RC_SCRIPTING_1 =        300,
    RC_SCRIPTING_2 =        301,
    RC_SCRIPTING_3 =        302,
    RC_SCRIPTING_4 =        303,
    RC_SCRIPTING_5 =        304,
    RC_SCRIPTING_6 =        305,
    RC_SCRIPTING_7 =        306,
    RC_SCRIPTING_8 =        307,
} RC_AuxFunc_t;

typedef enum {
    RC_IGNORE_RECEIVER       = (1 << 0), // RC receiver modules
    RC_IGNORE_OVERRIDES      = (1 << 1), // MAVLink overrides
    RC_IGNORE_FAILSAFE       = (1 << 2), // ignore RC failsafe bits
    RC_FPORT_PAD             = (1 << 3), // pad fport telem output
    RC_LOG_DATA              = (1 << 4), // log rc input bytes
    RC_ARMING_CHECK_THROTTLE = (1 << 5), // run an arming check for neutral throttle
    RC_ARMING_SKIP_CHECK_RPY = (1 << 6), // skip the an arming checks for the roll/pitch/yaw channels
    RC_ALLOW_SWITCH_REV      = (1 << 7), // honor the reversed flag on switches
} RCs_Option;

typedef struct
{
    // pwm is stored here
    int16_t     radio_in;

    // value generated from PWM normalised to configured scale
    int16_t     control_in;

    RC_ChannelType type_in;
    int16_t     high_in;

    // the input channel this corresponds to
    uint8_t     ch_in;

    // overrides
    uint16_t    override_value;
    uint32_t    last_override_time;

    //参数
    int16_t     _option; // e.g. activate EPM gripper / enable fence
    int16_t     _radio_min;
    int16_t     _radio_trim;
    int16_t     _radio_max;

    int8_t      _reversed;
    int16_t     _dead_zone;

    RC_SwitchState switch_state;
}RC_HandleTypeDef;

typedef struct
{
    uint32_t last_update_ms;
    bool     has_new_overrides;
    bool     has_had_rc_receiver; // true if we have had a direct detach RC reciever, does not include overrides

    // Allow override by default at start
    bool     gcs_overrides_enabled;    //默认是1

    //参数
    float    _override_timeout;
    int32_t  _options;
    int32_t  _protocols;

    RC_HandleTypeDef channel[RC_INPUT_MAX_CHANNELS];
}RCs_HandleTypeDef;

/*----------------------------------variable----------------------------------*/
extern RCs_HandleTypeDef Rcs;
extern RCs_HandleTypeDef *pRcs;
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
void        RC_init(RC_HandleTypeDef *pRc);
// setup the control preferences
void        RC_set_range(RC_HandleTypeDef *pRc, uint16_t high);
uint16_t    RC_get_range(RC_HandleTypeDef *pRc);
void        RC_set_angle(RC_HandleTypeDef *pRc, uint16_t angle);
bool        RC_get_reverse(RC_HandleTypeDef *pRc);
void        RC_set_default_dead_zone(RC_HandleTypeDef *pRc, int16_t dzone);
uint16_t    RC_get_dead_zone(RC_HandleTypeDef *pRc);

// get the center stick position expressed as a control_in value
int16_t     RC_get_control_mid(RC_HandleTypeDef *pRc);

// read input from hal.rcin - create a control_in value
bool        RC_update(RC_HandleTypeDef *pRc, int16_t ChanVal);
void        RC_recompute_pwm_no_deadzone(RC_HandleTypeDef *pRc);

void        RC_clear_override(RC_HandleTypeDef *pRc);
void        RC_set_override(RC_HandleTypeDef *pRc, const uint16_t v, const uint32_t timestamp_ms);
bool        RC_has_override(RC_HandleTypeDef *pRc);

//convert a pulse width modulation value to a value in the configured range
int16_t     RC_pwm_to_range(RC_HandleTypeDef *pRc);

//convert a pulse width modulation value to a value in the configured
//range, using the specified deadzone
int16_t     RC_pwm_to_range_dz(RC_HandleTypeDef *pRc, uint16_t _dead_zone);

//return an "angle in centidegrees" (normally -4500 to 4500) from
//the current radio_in value
int16_t     RC_pwm_to_angle(RC_HandleTypeDef *pRc);
int16_t     RC_pwm_to_angle_dz(RC_HandleTypeDef *pRc, uint16_t _dead_zone);
int16_t     RC_pwm_to_angle_dz_trim(RC_HandleTypeDef *pRc, uint16_t _dead_zone, uint16_t _trim);

// return a normalised input for a channel, in range -1 to 1,
// centered around the channel trim. Ignore deadzone.
float       RC_norm_input(RC_HandleTypeDef *pRc);

// return a normalised input for a channel, in range -1 to 1,
// centered around the channel trim. Take into account the deadzone
float       RC_norm_input_dz(RC_HandleTypeDef *pRc);

// return a normalised input for a channel, in range -1 to 1,
// ignores trim and deadzone
float       RC_norm_input_ignore_trim(RC_HandleTypeDef *pRc);

uint8_t     RC_percent_input(RC_HandleTypeDef *pRc);

// return true if input is within deadzone of trim
bool        RC_in_trim_dz(RC_HandleTypeDef *pRc);

int16_t     RC_stick_mixing(RC_HandleTypeDef *pRc, const int16_t servo_in);

// get control input with zero deadzone
int16_t     RC_get_control_in_zero_dz(RC_HandleTypeDef *pRc);

void        RC_init_aux(RC_HandleTypeDef *pRc);
bool        RC_read_aux(RC_HandleTypeDef *pRc);

// init_aux_switch_function - initialize aux functions
void        RC_init_aux_function(RC_HandleTypeDef *pRc, const RC_AuxFunc_t ch_option, const RC_AuxSwitchPos ch_flag);
void        RC_do_aux_function(RC_HandleTypeDef *pRc, const RC_AuxFunc_t ch_option, const RC_AuxSwitchPos ch_flag);
void        RC_do_aux_function_armdisarm(const RC_AuxSwitchPos ch_flag);

// read_3pos_switch
bool        RC_read_3pos_switch(RC_HandleTypeDef *pRc, RC_AuxSwitchPos *ret);
bool        RC_debounce_completed(RC_HandleTypeDef *pRc, int8_t position);

RC_AuxSwitchPos  RC_get_aux_switch_pos(RC_HandleTypeDef *pRc);

void        RC_mode_switch_changed(RC_HandleTypeDef *pRc, modeswitch_pos_t new_pos);
void        RC_reset_mode_switch(RC_HandleTypeDef *pRc);
void        RC_read_mode_switch(RC_HandleTypeDef *pRc);

void        RC_register_callback(bool (*cb)(int8_t mode, int8_t reason));


// RCs_HandleTypeDef相关函数
void        RCs_init();
void        RCs_init_aux_all();

void        RCs_read_aux_all();

bool        RCs_read_input();

RC_HandleTypeDef *RCs_flight_mode_channel()
;
uint8_t     RCs_flight_mode_channel_number();

void        RCs_reset_mode_switch();
void        RCs_read_mode_switch();

bool        RCs_get_override_timeout_ms(uint32_t *returned_timeout_ms);
bool        RCs_ignore_receiver();

// returns true if we have had a direct detach RC reciever, does not include overrides
bool        RCs_has_had_rc_receiver();

// should a channel reverse option affect aux switches
bool        RCs_switch_reverse_allowed();

uint8_t     RCs_get_radio_in(uint16_t *chans, const uint8_t num_channels);

bool        RCs_has_valid_input();
void        RCs_clear_overrides();

bool        RCs_has_active_overrides();

void        RCs_AssignParam();

RC_HandleTypeDef *RCs_find_channel_for_option(const RC_AuxFunc_t option);

uint8_t     RCs_get_valid_channel_count(void);

// duplicate_options_exist - returns true if any options are duplicated
bool RCs_duplicate_options_exist();

// check if flight mode channel is assigned RC option
// return true if assigned
bool RCs_flight_mode_channel_conflicts_with_rc_option();

uint32_t RCs_enabled_protocols();

RC_HandleTypeDef *RCs_get_channel(const uint8_t ch);
/*------------------------------------test------------------------------------*/

#ifdef __cplusplus
}
#endif



